package com.zrq.skinchange.skin;

import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.os.AsyncTask;

import com.zrq.skinchange.skin.attr.SkinView;
import com.zrq.skinchange.skin.callback.ISkinChangeListener;
import com.zrq.skinchange.skin.callback.ISkinChangingCallback;

import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by huwei on 2017/8/8.
 */

public class SkinManager {
    private Context mContext;

    private static SkinManager sInstance;

    private ResourceManager mResourceManager;

    private List<ISkinChangeListener> mListeners = new ArrayList<ISkinChangeListener>();

    private Map<ISkinChangeListener, List<SkinView>> mSkinViewMaps =
            new HashMap<ISkinChangeListener, List<SkinView>>();

    private PrefUtils mPrefUtils;

    private String mCurPath;
    private String mCurPkg;
    private String mSuffix;


    private SkinManager() {

    }

    public static SkinManager getInstanc() {
        if (sInstance == null) {
            synchronized (SkinManager.class) {
                if (sInstance == null) {
                    sInstance = new SkinManager();
                }
            }
        }
        return sInstance;
    }

    public void init(Context context) {
        mContext = context.getApplicationContext();
        mPrefUtils = new PrefUtils(mContext);

        try {
            String plugPath = mPrefUtils.getPlugPath();
            String pluginPkg = mPrefUtils.getPluginPkg();
            mSuffix = mPrefUtils.getSuffix();

            File file = new File(plugPath);
            if (file.exists()) {
                loadPlugin(plugPath, pluginPkg);
            }
        } catch (Exception e) {
            e.printStackTrace();
            mPrefUtils.clear();
        }
    }


    public ResourceManager getResourceManager() {
        if (!usePlugin()) {
            return new ResourceManager(mContext.getResources(), mContext.getPackageName(), mSuffix);
        }

        return mResourceManager;
    }

    private void loadPlugin(String skinPluginPath, String skinPluginPKg) throws Exception{

            if (skinPluginPath.equals(mCurPath) && skinPluginPKg.equals(mCurPkg)) {
                return;
            }
            AssetManager assetManager = AssetManager.class.newInstance();
            Method addAssetPathMethod = assetManager.getClass().getMethod("addAssetPath", String.class);
            addAssetPathMethod.invoke(assetManager, skinPluginPath);
            Resources superResources = mContext.getResources();
            Resources resources = new Resources(assetManager, superResources.getDisplayMetrics(),
                    superResources.getConfiguration());
            mResourceManager = new ResourceManager(resources, skinPluginPKg, null);

            mCurPath = skinPluginPath;
            mCurPkg = skinPluginPKg;

    }


    public List<SkinView> getSkinViews(ISkinChangeListener listener) {
        return mSkinViewMaps.get(listener);
    }

    public void addSkinView(ISkinChangeListener listener, List<SkinView> views) {
        mSkinViewMaps.put(listener, views);
    }

    public void registerListener(ISkinChangeListener listener) {
        mListeners.add(listener);
    }

    public void unRegisterListener(ISkinChangeListener listener) {
        mListeners.remove(listener);
        mSkinViewMaps.remove(listener);
    }

    public void changeSkin(String suffix) {
        clearPluginInfo();

        mSuffix = suffix;

        mPrefUtils.saveSuffix(suffix);
        notifyChangeListener();
    }

    private void clearPluginInfo() {
        mCurPath = null;
        mCurPkg = null;
        mSuffix = null;
        mPrefUtils.clear();
    }

    public void changeSkin(final String skinPluginPath, final String skinPluginPKg, ISkinChangingCallback callback) {

        if (callback == null) {
            callback = ISkinChangingCallback.DEFAULT_CALLBACK;
        }
        final ISkinChangingCallback finalCallback = callback;

        finalCallback.onStart();
        new AsyncTask<Void, Void, Integer>() {

            @Override
            protected Integer doInBackground(Void... params) {
                try {
                    loadPlugin(skinPluginPath, skinPluginPKg);
                } catch (Exception e) {
                    e.printStackTrace();
                    return -1;
                }

                return 0;
            }

            @Override
            protected void onPostExecute(Integer code) {

                if (code == -1) {
                    finalCallback.onError(null);
                    return;
                }
                try {
                    notifyChangeListener();
                    finalCallback.onComplete();
                    updatePlugInfo(skinPluginPath, skinPluginPKg);

                } catch (Exception e) {
                    e.printStackTrace();
                    finalCallback.onError(e);
                }

            }
        }.execute();

    }

    private void updatePlugInfo(String path, String pkg) {
        mPrefUtils.savePluginPath(path);
        mPrefUtils.savePluginPkg(pkg);
    }

    private void notifyChangeListener() {
        for (ISkinChangeListener listener : mListeners) {

            skinChanged(listener);

            listener.onSkinChanged();
        }
    }

    public void skinChanged(ISkinChangeListener listener) {

        List<SkinView> skinViews = mSkinViewMaps.get(listener);

        for (SkinView skinView : skinViews) {
            skinView.apply();
        }
    }

    public boolean needChangeSkin() {
        return usePlugin() || useSuffix();
    }

    private boolean usePlugin() {
        return mCurPath != null && !mCurPath.trim().equals("");
    }

    private boolean useSuffix() {
        return mSuffix != null && !mSuffix.trim().equals("");
    }
}
